package com.demo.app.config;


import com.demo.app.service.MyUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Resource
   private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

   @Resource
   private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

   @Resource
   private MyUserDetailsService myUserDetailsService;

   @Resource
   MyLogoutSuccessHandler myLogoutSuccessHandler;

   
   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.csrf().disable()
        .formLogin()//开启httpbasic认证
              .loginPage("/login.html")//一旦用户的请求没有权限就跳转到这个页面
              .loginProcessingUrl("/login")//登录表单form中action的地址，也就是处理认证请求的路径
              .usernameParameter("uname")///登录表单form中用户名输入框input的name名，不修改的话默认是username
              .passwordParameter("pword")//form中密码输入框input的name名，不修改的话默认是password
              //.defaultSuccessUrl("/")//登录认证成功后默认转跳的路径
              //.failureUrl("/login.html")//登陆失败跳转路径
              .successHandler(myAuthenticationSuccessHandler)
              .failureHandler(myAuthenticationFailureHandler)
      .and()
              .authorizeRequests()
              .antMatchers("/login.html","/login").permitAll()//不需要通过登录验证就可以被访问的资源路径
              .anyRequest()
                  .access("@rbacService.hasPermission(request,authentication)")
              /*.antMatchers("/","/biz1","/biz2") //资源路径匹配
                  .hasAnyAuthority("ROLE_user","ROLE_admin")  //user角色和admin角色都可以访问
              *//*.antMatchers("/syslog","/sysuser")  //资源路径匹配
                  .hasAnyRole("admin")  //admin角色可以访问*//*
              .antMatchers("/syslog").hasAuthority("/syslog")
              .antMatchers("/sysuser").hasAuthority("/sysuser")
              .anyRequest()
              .authenticated()*/
      .and().logout()
              .logoutUrl("/signout")
              //.logoutSuccessUrl("/login.html")
              .deleteCookies("JSESSIONID")
              .logoutSuccessHandler(myLogoutSuccessHandler)
      .and().rememberMe()
              .rememberMeParameter("remember-me-new")
              .rememberMeCookieName("remember-me-cookie")
              .tokenValiditySeconds(2 * 24 * 60 * 60)
              .tokenRepository(persistentTokenRepository())
      .and().sessionManagement()
              .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
              .sessionFixation().migrateSession()
              .maximumSessions(1)
              .maxSessionsPreventsLogin(false)
              .expiredSessionStrategy(new CustomExpiredSessionStrategy());
              //.invalidSessionUrl("/invalidSession.html");
   }

   @Override
   public void configure(AuthenticationManagerBuilder auth) throws Exception {
      /*.inMemoryAuthentication()
              .withUser("user")
              .password(passwordEncoder().encode("123456"))
              .roles("user")
           .and()
              .withUser("admin")
              .password(passwordEncoder().encode("123456"))
              .authorities("sys:log","sys:user")
              //.roles("admin")*/
      auth.userDetailsService(myUserDetailsService)
          .passwordEncoder(passwordEncoder());//配置BCrypt加密
   }

   @Bean
   public PasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
   }

   @Override
   public void configure(WebSecurity web) {
      //将项目中静态资源路径开放出来
      web.ignoring().antMatchers( "/css/**", "/fonts/**", "/img/**", "/js/**","/favicon.ico");
   }

   @Resource
   private DataSource dataSource;

   @Bean
   public PersistentTokenRepository persistentTokenRepository(){
      JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
      tokenRepository.setDataSource(dataSource);
      return tokenRepository;
   }

   @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
   @Override
   public AuthenticationManager authenticationManagerBean() throws Exception {
      return super.authenticationManagerBean();
   }

}